package com.qidian.server.servlet;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.RequestContext;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.servlet.ServletRequestContext;
import org.apache.log4j.Logger;

import com.qidian.common.Constants;
import com.qidian.common.Globals;
import com.qidian.server.MServer;
import com.qidian.server.Status;


public class FileServlet extends HttpServlet 
{
    private static final long serialVersionUID = -667253418809572503L;
    private static final Logger logger = Logger.getLogger(FileServlet.class.getName()); 
    private static final MServer mserver = MServer.getInstance() ;
    
    //媒体对象上传的绝对路径，在Servlet初始化时，进行赋值 
    private static String uploadDir = null ;
    private static String relativDir = null ;
    

	/**
	 * The doPost method of the servlet. <br>
	 *
	 * This method is called when a form has its tag value method equals to post.
	 * 
	 * @param request the request send by the client to the server
	 * @param response the response send by the server to the client
	 * @throws ServletException if an error occurred
	 * @throws IOException if an error occurred
	 */
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException 
	{

		Status status = Status.OK ;

        String actionType = request.getParameter(ServletConstants.arg_action_type) ;
//        logger.debug(request.getQueryString()) ;
//        System.out.println(request.getQueryString());
        
        //  检查参数
        if ("sendFile".equalsIgnoreCase(actionType))
            status = sendFile(request,response) ;
        else 
        	status = Status.INVALID_VALUE ;  

		if (status != Status.OK)
		{
		    response.setCharacterEncoding("utf8") ;
		    response.getWriter().write(status.statusCode.toString()) ;
		}
	}

	private Status sendFile(HttpServletRequest request,
			HttpServletResponse response) throws IOException 
	{
        String account = request.getParameter(ServletConstants.arg_account) ;
        String strGameType = request.getParameter(ServletConstants.arg_game_type) ;
        String strInterval = request.getParameter(ServletConstants.arg_interval) ;
        String userName = request.getParameter(ServletConstants.arg_user_name) ;
        String strPoint = request.getParameter(ServletConstants.arg_point) ;// 扣点数
        String returnUser = request.getParameter(ServletConstants.arg_return_user) ;// 返点用户
        if ( strGameType == null || strInterval == null || account == null )
        	return Status.INVALID_ARGUMENT ;
        
        // 预检查
        Status status = Status.OK ;
        status = mserver.p2s_preSendFile(userName, account, strGameType) ;
        if (status != Status.OK)
        	return status ;
        
//        // 不绑定用户、不返点，返回给admin360
//        if (userName == null && returnUser == null)
//        	returnUser = Constants.return_user_name ;
        
    	String fromIp = request.getRemoteAddr();
    	String xIp = request.getHeader("X-Real-IP") ;
    	if (xIp != null) 
    		fromIp  = xIp;
    	
    	int fromPort = request.getRemotePort() ;
		// 上传媒体对象
		Object[] result = new Object[2] ;
		try 
		{
			if( sendFile(request,result) != Status.OK)
				return Status.FILE_UPLOAD_FAILURE;
		} catch (Exception e) {
//			e.printStackTrace() ;
			logger.error(e+":"+fromIp+":"+fromPort) ;			
			return Status.FILE_UPLOAD_FAILURE ;
		}
		
		int gameType = Integer.parseInt(strGameType)  ;
        int interval = Integer.parseInt(strInterval) ;
		String contentType = (String)result[0] ;
		byte[] content = (byte[])result[1] ; 
		int point = -1 ;
//		String returnUser = null ;
		if (strPoint != null)
			point = Integer.parseInt(strPoint) ;
		
		StringBuffer resultMsgId = new StringBuffer(10) ;
		status = mserver.p2s_sendFile(contentType, content, 
				userName,account, gameType, interval, fromIp, fromPort, 
				point,returnUser,resultMsgId);
		if (status == Status.OK)
			response.getWriter().write(resultMsgId.toString()) ;
		return status ;
		
		
//        // 生成消息
//		msgId = Globals.getIDGenerator().getNextId() ;
//        MessageBean message = new MessageBean() ;
//        message.setReceiveTime(System.currentTimeMillis()) ;
//        message.setId(msgId) ;
//        message.setAccountId(account.getAccountId()) ;
//        message.setGameType(gameType) ;
//        // 如果是自定义超时时间
//        if(gameTypeBean.isUdfInterval())
//        	message.setInterval(interval) ;
//        else
//        	message.setInterval(gameTypeBean.getMinInterval());
//        
//        message.setIp(request.getRemoteAddr()) ;
//        message.setPort(request.getRemotePort()) ;
//        message.setStatus(MessageStatus.WAIT_TO_ANSWER.status) ;
//        message.setContent(content) ;
//        message.setContentType(contentType) ;
//        	
//        // 缓存消息
//        if(!Globals.getMessageBuffer().add(message))
//        	return Status.SERVER_TOO_BUSY ;
//        // 分配消息,增加用户已用点数
//        account.increaseUsedPoint(point) ;
//        user.increaseUsedPoint(point) ;
//        
//        // 输出结果
//		response.getWriter().write(msgId.toString()) ;
//        
//        return Status.OK ;
	}


	/**
	 * 初始化 <br>
	 *
	 * @throws ServletException if an error occurs
	 */
	public void init() throws ServletException 
	{
		relativDir = Globals.getUploadRelativePath() ;
	    uploadDir = this.getServletConfig().getServletContext().getRealPath("/")+relativDir ;
	    
	    
	    Globals.setUploadDirAbsolutePath(uploadDir) ;
	    File file = new File(uploadDir ) ;
	    if (!file.exists())
	        file.mkdirs() ;
	    System.out.println("Upload dir " + uploadDir);
	}
	


	public void doGet(HttpServletRequest request, HttpServletResponse response)
	throws ServletException, IOException 
    {
	    Status status = Status.OK ;
	    String actionType = request.getParameter(ServletConstants.arg_action_type) ;
	    
	    if ("getFile".equalsIgnoreCase(actionType))
	    	status = getFile(request,response);
	    else
	    	status = Status.INVALID_ARGUMENT ;
	    if (status != Status.OK)
	    {
		    response.setCharacterEncoding("utf8") ;
	    	response.getWriter().write(status.description) ;
	    }
    }


	private Status getFile(HttpServletRequest request,
            HttpServletResponse response) throws IOException
    {
	    Status status = Status.OK ;
	    String strMsgId = request.getParameter(ServletConstants.arg_msg_id) ;
	    if (strMsgId  == null)
	    	return Status.INVALID_ARGUMENT ;
	    StringBuffer contentType = new StringBuffer(8) ;
	    byte[] content = mserver.c2s_getFile(strMsgId,contentType) ;
	    if (content == null)
	    {
	    	logger.error("Failed to get file:"+strMsgId+":"+request.getRemoteAddr()+":"+request.getRemotePort()) ;
	    	status = Status.INVALID_VALUE ;
	    }
	    else
	    {
	    	String mimeType = ServletConstants.contentTypeMapping.get(contentType.toString()) ;
	        response.setContentType(mimeType) ;
        	ServletOutputStream os = response.getOutputStream();
            os.write(content) ;
            os.close();
	    }
        return status;
    }

    /**
     * 媒体文件上传
     * 
     * @param request multipurtServletRequest
     * @return 媒体类型和媒体内容
     * @throws FileUploadException 
     * @throws IOException 
     * @throws Exception 
     */
    private Status sendFile(HttpServletRequest request, Object[] resultObjects) throws FileUploadException, IOException
    {
        byte[] content = null ;
        String contentType = null ;

        RequestContext requestContext = new ServletRequestContext(request);  
        if(!FileUpload.isMultipartContent(requestContext))
        	return Status.INVALID_ARGUMENT ;
        
        DiskFileItemFactory factory = new DiskFileItemFactory();
        // 64K
        factory.setSizeThreshold(Constants.maxUploadSize) ;
        ServletFileUpload upload = new ServletFileUpload(factory);
        upload.setSizeMax(Constants.maxUploadSize);
        List<?> items = upload.parseRequest(request);
        if(items.size() != 1)
        	return Status.INVALID_ARGUMENT ;
        for(int i = 0 ; i < items.size() ; i++)
        {
        	FileItem fileItem = (FileItem)items.get(i) ;
            if(ServletConstants.arg_file.equalsIgnoreCase(fileItem.getFieldName()))
            {

            	// 类型
                if (fileItem.getContentType() != null)
                {
                	String ct = fileItem.getContentType().split(";")[0] ;
                	contentType = ServletConstants.contentTypeMapping.get(ct.toLowerCase()) ;
                }
                else
                	contentType = "" ;
                
                // 内容
                if (fileItem.isInMemory())
                {
                	content = fileItem.get() ;
                	fileItem.delete();
                }
                else
                {
	                InputStream is = fileItem.getInputStream() ;
	                int fileLen = (int)fileItem.getSize() ;
	                content = new byte[fileLen] ;
	                int readLen = is.read(content, 0, fileLen) ;
	                if (readLen != fileLen)
	                {
	                	is.close() ;
	                	fileItem.delete() ;
	                	return Status.OTHER_ERROR ;
	                }
	                is.close() ;
	                fileItem.delete() ;
                }
            }
        }
        
        if (content == null)
        	return Status.INVALID_ARGUMENT ;

        resultObjects[0] = contentType ;
        resultObjects[1] = content ;
        return Status.OK;
    }
	

}
